﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

namespace Windows8Accelerator.Core.Xaml.Controls.Charts
{
    [TemplatePart(Name = "Canvas", Type = typeof(Canvas))]
    public class SuperBarChart : Control
    {
        public SuperBarChart()
        {
            DefaultStyleKey = typeof(SuperBarChart);
        }

        public DataSeries Series
        {
            get { return (DataSeries)GetValue(SeriesProperty); }
            set { SetValue(SeriesProperty, value); }
        }
        public static readonly DependencyProperty SeriesProperty =
            DependencyProperty.Register("Series", typeof(DataSeries), typeof(SuperBarChart), new PropertyMetadata(new DataSeries(), SeriesPropertyChanged));

        private static void SeriesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((SuperBarChart)d).Update();
        }

        protected override void OnApplyTemplate()
        {
            Canvas = GetTemplateChild("Canvas") as Canvas;
            Update();
        }

        public void Update()
        {
            var desiredWidth = 300.0;
            var desiredHeight = 200.0;

            if (Canvas != null)
            {
                Canvas.Children.Clear();

                if (Series == null || Series.Series == null || Series.Series.Count == 0)
                    return;

                var minX = Series.GetMinX();
                var width = Series.GetMaxX() -minX + 1;
                var normalizedWidthFactor = desiredWidth / width;
                var normalizedWidth = width * normalizedWidthFactor;

                var minValue = Math.Min(0, Series.GetMinY());
                var maxValue = Math.Max(0,Series.GetMaxY() );
                var height = maxValue - minValue;
                var normalizedHeightFactor = desiredHeight / height;
                var normalizedHeight = height * normalizedHeightFactor;              

                var xLabelHeight = 50.0;
                var yLabelWidth = 80.0;

                if (Series.Series.Count > 0)
                {
                    var serie = Series.Series[0];
                    var itemTemplate = serie.GetItemTemplate();
                    var xLabelTemplate = serie.GetXLabelTemplate();
                    var yLabelTemplate = serie.GetYLabelTemplate();
                    Canvas.Width = normalizedWidth + yLabelWidth;
                    Canvas.Height = normalizedHeight + xLabelHeight;

                    var yValueToString = serie.YValueToString;
                    if (yValueToString == null)
                        yValueToString = (d) => d.ToString();

                    var yScaleSize1 = height / 10;
                    for (double i = 0.0000001; i < 100000000; i*=10)
                    {
                        if (height / i < 10)
                        {
                            yScaleSize1 = i;
                            break;
                        }
                    }
                    if (yScaleSize1 == 0)
                        yScaleSize1 = 1;

                    var scaleMax = Math.Ceiling(maxValue / yScaleSize1);
                    var scaleMin = Math.Floor(minValue / yScaleSize1);

                    while (scaleMax - scaleMin < 5)
                    {
                        yScaleSize1 = yScaleSize1/10;
                        scaleMax = Math.Ceiling(maxValue / yScaleSize1);
                        scaleMin = Math.Floor(minValue / yScaleSize1);
                    }
                    scaleMax = Math.Min(scaleMax, Int32.MaxValue);
                    scaleMin = Math.Max(scaleMin, Int32.MinValue);

                    var normalizedZero = scaleMax * yScaleSize1 * normalizedHeightFactor;

                    normalizedHeight = (scaleMax - scaleMin) *yScaleSize1 * normalizedHeightFactor;
                    Canvas.Height = normalizedHeight + xLabelHeight;

                    for (int i = Convert.ToInt32(scaleMin); i < scaleMax + 1; i++)
                    {
                        var labelItem = new LabelDataItem()
                        {
                            Margin = new Thickness(4, 0, 4, 0),
                            Height = yScaleSize1 * normalizedHeightFactor,
                            Width = normalizedWidth + yLabelWidth,
                            X = 0,
                            Y = normalizedZero - ((i * yScaleSize1) * normalizedHeightFactor),
                            Label = yValueToString(i * yScaleSize1),
                        };

                        var yLabelControl = new ContentControl()
                        {
                            ContentTemplate = yLabelTemplate,
                            Content = labelItem,
                        };
                        yLabelControl.SetBinding(Canvas.LeftProperty, new Binding() { Source = labelItem, Path = new PropertyPath("X") });
                        yLabelControl.SetBinding(Canvas.TopProperty, new Binding() { Source = labelItem, Path = new PropertyPath("Y") });
                        Canvas.Children.Add(yLabelControl);
                    }

                    for (int index = 0; index < serie.GetCount(); index++)
                    {
                        var value = serie.GetYAsDouble(index);
                        var y = value >= 0 ? normalizedZero - (value * normalizedHeightFactor) : normalizedZero;

                        var dataPointItem = new DataPointItem()
                        {
                            Margin = new Thickness(8, 0, 8, 0),
                            Height = Math.Abs(serie.GetYAsDouble(index)) * normalizedHeightFactor,
                            Width = normalizedWidthFactor,
                            X = ((serie.GetXAsDouble(index) - minX) * normalizedWidthFactor) + yLabelWidth,
                            XLabel = serie.GetXLabel(index),
                            XValue = serie.GetX(index).ToString(),
                            Y = y,
                            YLabel = serie.GetYLabel(index),
                            YValue = yValueToString(serie.GetYAsDouble(index)),
                            YValueVerticalAlignment = value >= 0 ? VerticalAlignment.Top : VerticalAlignment.Bottom,
                        };
                        var dataControl = new ContentControl()
                        {
                            ContentTemplate = itemTemplate,
                            Content = dataPointItem,
                        };
                        dataControl.SetBinding(Canvas.LeftProperty, new Binding() { Source = dataPointItem, Path = new PropertyPath("X") });
                        dataControl.SetBinding(Canvas.TopProperty, new Binding() { Source = dataPointItem, Path = new PropertyPath("Y") });
                        Canvas.Children.Add(dataControl);

                        var labelItem = new LabelDataItem()
                        {
                            Margin = new Thickness(4, 0, 4, 0),
                            Height = xLabelHeight,
                            Width = normalizedWidthFactor,
                            X = ((serie.GetXAsDouble(index) - minX) * normalizedWidthFactor) + yLabelWidth,
                            Y = Canvas.Height - xLabelHeight,
                            Label = serie.GetXLabel(index),
                        };
                        var xLabelControl = new ContentControl()
                        {
                            ContentTemplate = xLabelTemplate,
                            Content = labelItem,
                        };
                        xLabelControl.SetBinding(Canvas.LeftProperty, new Binding() { Source = labelItem, Path = new PropertyPath("X") });
                        xLabelControl.SetBinding(Canvas.TopProperty, new Binding() { Source = labelItem, Path = new PropertyPath("Y") });
                        Canvas.Children.Add(xLabelControl);
                    }


                   
                }
            }
        }

        private Canvas Canvas;
    }
}
